/***************************************************************
 * Name:      SetupCreatorMain.cpp
 * Purpose:   Code for Application Frame
 * Author:    Jeremie Fouche (jeremie.fouche@gmail.com)
 * Created:   2007-05-05
 * Copyright: Jeremie Fouche ()
 * License:
 **************************************************************/

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__

#include "creatorframe.h"
#include "sc/interface.h"

#include "boost/foreach.hpp"

#include "utils/traceur.h"

#define foreach BOOST_FOREACH


/// EVENT TABLE
BEGIN_EVENT_TABLE(CreatorFrame, CreatorFrameGui)
END_EVENT_TABLE()

/**
* CreatorFrame constructor
*
* @param parent parent window (NULL)
*/
CreatorFrame::CreatorFrame(wxWindow* parent)
: CreatorFrameGui(parent)
{
    SetIcon(wxICON(A));
}

/**
* Load all the information in the frame :
*  - Create the tab for the xml file(s)
*  - Fill the tree
*/
void CreatorFrame::Load(void)
{
    m_notebook->DeleteAllPages();

    for (size_t idx = 0; idx < m_context.GetSetupCount(); ++idx)
    {
        const sc::SetupContext* pcSetupCtx = m_context.GetSetupContext(idx);
        assert(pcSetupCtx != NULL);

        const sc::Setup& rcSetup = pcSetupCtx->GetSetup();

        CreatorPanel* panel = AddPage(pcSetupCtx->GetXmlFile().c_str());

Traceur::Printf("CreatorFrame::Load - page %d", idx);

        std::string sRoot;
        int error = rcSetup.GetConfig().GetRoot(sRoot);
        if (!error)
        {
            const sc::cfg::TElements& rcElements = rcSetup.GetConfig().GetElements();
            sc::cfg::TElements::const_iterator iterElem = rcElements.find(sRoot);

            assert(iterElem != rcElements.end());

            panel->AddTreeChild(wxTreeItemId(), iterElem->second);
        }
    }
}

/**
* Add a new page to the notebook, corresponding to the setup (xml) file
*
* @param sName  xml file name, which will be the page title
*/
CreatorPanel* CreatorFrame::AddPage(const wxString& sName)
{
    size_t idx = m_notebook->GetPageCount();

    assert(idx <= m_context.GetSetupCount());

    CreatorPanel* panel = new CreatorPanel(m_notebook, m_context.GetSetupContext(idx));
    m_notebook->AddPage(panel, sName);
    return panel;
}

/**
* Load a context
*
* @param sFilename
*
* @return the context loading error
*/
int CreatorFrame::LoadContext(const wxString& sFilename)
{
    int error = m_context.Load(sFilename.c_str());
    if (!error)
    {
        Load();
    }
    else
    {
        wxString sError = wxString::Format(_T("Loading context : error %d !"), error);
        ::wxMessageBox(sError, _T("Setup Creator"), wxOK | wxICON_ERROR);
    }
    return error;
}

/**
* Called by the framework to open a context file
*
* @param event
*/
void CreatorFrame::OnFileOpen( wxCommandEvent& event )
{
	wxFileDialog dlg(this);
	dlg.SetWildcard( wxT("Setup creator context files (*.scc)|*.scc") );
	if (dlg.ShowModal() == wxID_OK)
	{
        int error = LoadContext(dlg.GetPath());
        if (!error)
        {
            Load();
        }
	}
}

/**
* Called by the framework to save the context to the current file
*
* @param event
*/
void CreatorFrame::OnFileSave( wxCommandEvent& event )
{
/**
    int error = m_context.SaveContext();
    if (error)
    {
        wxString sError = wxString::Format(_T("Saving error : %d"), error);
        wxMessageBox(sError);
    }
*/
}

/**
* Called by the framework to save the context to a new file
*
* @param event
*/
void CreatorFrame::OnFileSaveAs( wxCommandEvent& event )
{
	wxFileDialog dlg(this);
	dlg.SetWildcard( wxT("Setup creator context file files (*.scc)|*.scc") );
	if (dlg.ShowModal() == wxID_OK)
	{
	    m_context.SetFile(dlg.GetPath().c_str());
	    OnFileSave(event);
	}
}

/**
* Called by the framework when the user need to quit the application
*
* @param event
*/
void CreatorFrame::OnFileExit( wxCommandEvent& event )
{
    Destroy();
}




/**
* CreatorPanel constructor.
*
* @param parent    parent window
* @param rContext  The setup creator context
*/
CreatorPanel::CreatorPanel(wxWindow* parent, sc::SetupContext* pContext)
: CreatorPanelGui(parent)
, m_pContext(pContext)
{
    assert(pContext != NULL);

    m_editXml->SetValue(m_pContext->GetXmlFile().c_str());
    m_editRng->SetValue(m_pContext->GetConfigFile().c_str());

    m_pgmConfig->AddPage();
    m_pgmContext->AddPage();
    m_notebook->SetPageText(0, _T("Configuration"));
    m_notebook->SetPageText(1, _T("Context"));
}

/**
* Add a child and it's children to the tree.
*
* @param hParent    handle to the tree item parent
* @param rcElement  element to be added to the tree
*
* @return handle to the tree item created
*/
wxTreeItemId CreatorPanel::AddTreeChild(const wxTreeItemId& hParent, const sc::cfg::Element& rcElement)
{
Traceur::Printf("CreatorPanel::AddTreeChild(%s) - 1", rcElement.GetName().c_str());

    // Create an invalid item
    wxTreeItemId newItem;

    // Add the child to the tree
    if (hParent.IsOk())
        newItem = m_treeCreator->AppendItem(hParent, rcElement.GetName().c_str());
    else
        newItem = m_treeCreator->AddRoot(rcElement.GetName().c_str());

Traceur::Printf("CreatorPanel::AddTreeChild(%s) - 2", rcElement.GetName().c_str());

    // Assign the Element to the new tree item
	ElementTID* ptid = new ElementTID( const_cast<sc::cfg::Element*>(&rcElement) );
	m_treeCreator->SetItemData(newItem, ptid);

Traceur::Printf("CreatorPanel::AddTreeChild(%s) - 3", rcElement.GetName().c_str());

	// Add the attributes
	foreach(const sc::cfg::Attribute& rcAttribute, rcElement.GetAttributes())
	{
Traceur::Printf( "CreatorPanel::AddTreeChild(%s) - 4* - 1 - Attribute %s"
               , rcElement.GetName().c_str()
               , rcAttribute.GetName().c_str()
               );

//std::ostringstream oss;
//oss << rcAttribute;
//OutputDebugString(oss.str().c_str());

	    wxTreeItemId idAttribute = m_treeCreator->AppendItem(newItem, rcAttribute.GetName().c_str());
	    m_treeCreator->SetItemTextColour(idAttribute, *wxBLUE);

        // Assign the Attribute to the attribute tree item
        ptid = new ElementTID( const_cast<sc::cfg::Element*>(&rcElement)
                             , const_cast<sc::cfg::Attribute*>(&rcAttribute)
                             );
        m_treeCreator->SetItemData(idAttribute, ptid);
	}

Traceur::Printf("CreatorPanel::AddTreeChild(%s) - 5", rcElement.GetName().c_str());

	// Add the existing children
	foreach (const sc::cfg::TChildren::value_type& rcChildValue, rcElement.GetChildren())
	{
Traceur::Printf( "CreatorPanel::AddTreeChild(%s) - 6* - 1 - Child %s"
               , rcElement.GetName().c_str()
               , rcChildValue->second.GetName().c_str()
               );

//std::ostringstream oss;
//oss << rcChildValue->second;
//OutputDebugString(oss.str().c_str());

		AddTreeChild(newItem, rcChildValue->second);
	}

    return newItem;
}

/**
* Set the Attribute to the property grids
*
* @param rcAttribute
*/
void CreatorPanel::SetAttribute(const sc::cfg::Attribute& rcAttribute) const
{
Traceur::Printf("CreatorPanel::SetAttribute(%s)", rcAttribute.GetName().c_str());

    /// Config
    m_pgmConfig->AppendCategory(_T("Attribute configuration"));

    // Config  - name
    wxPGId pgId = m_pgmConfig->Append( wxStringProperty( _T("Nom :")
                                                       , _T("name")
                                                       , rcAttribute.GetName().c_str()
                                                       )
                                     );
    m_pgmConfig->SetPropertyHelpString(pgId, _T("Nom de l'attribut XML."));

    // Config - type

    /// Context
    wxString sValue, sHelp;
    const sc::SetupContext::TMmiAttributes::const_iterator& iterMmiAttribute = m_pContext->GetMmiAttributes().find(rcAttribute.GetName());
    if (iterMmiAttribute != m_pContext->GetMmiAttributes().end())
    {
        sValue = iterMmiAttribute->second.sValue;
        sHelp  = iterMmiAttribute->second.sHelp;
    }

    m_pgmContext->AppendCategory(_T("Attribute Visualisation"));

    // Context - value
    pgId = m_pgmContext->Append( wxStringProperty( _T("Affichage :")
                                                , _T("value")
                                                , sValue
                                                )
                               );
    m_pgmContext->SetPropertyHelpString(pgId, _T("Texte affiche dans la liste des attributs."));

    // Context - default
    pgId = m_pgmContext->Append( wxLongStringProperty( _T("Aide :")
                                                     , _T("help")
                                                     , sHelp
                                                     )
                               );
    m_pgmContext->SetPropertyHelpString(pgId, _T("Texte affiche dans la zone d'aide en bas de la liste des attributs."));
}

/**
* Set the Element to the property grids
*
* @param rcElement
*/
void CreatorPanel::SetElement(const sc::cfg::Element& rcElement) const
{
Traceur::Printf("CreatorPanel::SetElement(%s)", rcElement.GetName().c_str());

    /// Config
    m_pgmConfig->AppendCategory(_T("Element configuration"));

    // Config  - name
    wxPGId pgId = m_pgmConfig->Append( wxStringProperty( _T("Nom :")
                                                       , _T("name")
                                                       , rcElement.GetName().c_str()
                                                       )
                                     );
    m_pgmConfig->SetPropertyHelpString(pgId, _T("Nom du noeud XML."));

    // Config - type
    wxPGChoices chsType;
    chsType.Add(wxT("Unique"),    sc::cfg::Element::UNIQUE);
    chsType.Add(wxT("Optionnal"), sc::cfg::Element::OPTION);
    chsType.Add(wxT("Multiple"),  sc::cfg::Element::MULTIPLE);
    pgId = m_pgmConfig->Append( wxEnumProperty( _T("Type :")
                                              , _T("type")
                                              , chsType
                                              , rcElement.GetType()
                                              )
                              );
    m_pgmConfig->SetPropertyHelpString(pgId, _T("type d'element XML."));

    /// Context
    wxString sValue, sDefault, sIcon;
    const sc::SetupContext::TMmiElements::const_iterator& iterMmiElement = m_pContext->GetMmiElements().find(rcElement.GetName());
    if (iterMmiElement != m_pContext->GetMmiElements().end())
    {
        sValue   = iterMmiElement->second.sValue.c_str();
        sDefault = iterMmiElement->second.sDefault.c_str();
//        sIcon    = m_pContext->FileRelativeToContext(iterMmiElement->second.sIcon).c_str();
    }

    m_pgmContext->AppendCategory(_T("Element Visualisation"));

    // Context - value
    pgId = m_pgmContext->Append( wxStringProperty( _T("Affichage :")
                                                , _T("value")
                                                , sValue
                                                )
                               );
    m_pgmContext->SetPropertyHelpString(pgId, _T("texte affiche dans l'arbre."));

    // Context - default
    pgId = m_pgmContext->Append( wxStringProperty( _T("Par defaut :")
                                                , _T("default")
                                                , sDefault
                                                )
                               );
    m_pgmContext->SetPropertyHelpString(pgId, _T("texte affiche dans l'arbre si aucun attribut n'est deja defini."));

    // Context - icon
    pgId = m_pgmContext->Append( wxFileProperty( _T("icon :")
                                               , _T("icon")
                                               , sIcon
                                               )
                               );
    m_pgmContext->SetPropertyHelpString(pgId, _T("Icon affiche dans l'arbre."));
}

/**
* Called by the framework before the user changed the selection of the config Element :
*  Save all Config and Context information
*
* @param event
*/
void CreatorPanel::OnTreeCreatorSelChanging( wxTreeEvent& event )
{
}

/**
* Called by the framework when the user changed the selection of the config Element :
*  Show context and configuration of the selected Element / Attribute
*
* @param event
*/
void CreatorPanel::OnTreeCreatorSelChanged( wxTreeEvent& event )
{
    m_pgmConfig->ClearPage(0);
    m_pgmContext->ClearPage(0);

    wxTreeItemId idSelection = m_treeCreator->GetSelection();

    // We try to get attribute, we get NULL if the selection is an Element
    sc::cfg::Attribute* pAttribute = GetAttribute(idSelection);
    sc::cfg::Element* pElement = GetElement(idSelection);
    if (pAttribute)
    {
        SetAttribute(*pAttribute);
    }
    else if (pElement)
    {
        SetElement(*pElement);
    }

    // Refresh to see the propertygrid information
    m_pgmConfig->Refresh();
    m_pgmContext->Refresh();
}

/**
* Get the config Element corresponding to a tree item
*
* @return the Element, or NULL
*/
sc::cfg::Element* CreatorPanel::GetElement(const wxTreeItemId& tid) const
{
    sc::cfg::Element* pElement = NULL;
    if (tid.IsOk())
    {
        ElementTID* pElemTID = dynamic_cast<ElementTID*>(m_treeCreator->GetItemData(tid));
        if (pElemTID)
        {
            pElement = pElemTID->m_pElement;
        }
    }
    return pElement;
}

/**
* Get the config Attribute corresponding to a tree item
*
* @return the Element, or NULL
*/
sc::cfg::Attribute* CreatorPanel::GetAttribute(const wxTreeItemId& tid) const
{
    sc::cfg::Attribute* pAttribute = NULL;
    if (tid.IsOk())
    {
        ElementTID* pElemTID = dynamic_cast<ElementTID*>(m_treeCreator->GetItemData(tid));
        if (pElemTID)
        {
            pAttribute = pElemTID->m_pAttribute;
        }
    }
    return pAttribute;
}
